<script setup lang="ts">
// 导出组件实例的类型
export interface TypeWriterInstance {
  // 在这里定义组件暴露的方法和属性
  isTyping: boolean;
}
const props = withDefaults(
  defineProps<{
    text: string;
    speed?: number;
    delay?: number;
    infinite?: boolean;
    // 新增自定义类名
    customClass?: string;
  }>(),
  {
    // 打字速度（毫秒/字符）
    speed: 100,
    // 开始前的延迟（毫秒）
    delay: 500,
    // 是否循环播放
    infinite: false,
    customClass: "",
  }
);

const displayedText = ref("");
const isTyping = ref(false);
const typingInterval = ref<number | null>(null);

/**
 * 模拟打字机效果的函数
 *
 * 此函数通过逐渐显示文本，模拟打字机的效果它首先将isTyping设置为true，
 * 然后逐个字符地显示props.text中的内容如果设置了props.infinite，
 * 则在完成一次显示后，暂停一段时间，然后重新开始显示文本
 */
const typeWriter = () => {
  // 清除之前的定时器
  if (typingInterval.value) {
    clearInterval(typingInterval.value);
    typingInterval.value = null;
  }
  isTyping.value = false;
  displayedText.value = "";

  let i = 0;
  typingInterval.value = setInterval(() => {
    if (i < props.text.length) {
      displayedText.value += props.text.charAt(i);
      i++;
    } else {
      if (typingInterval.value) {
        clearInterval(typingInterval.value);
        typingInterval.value = null;
      }

      isTyping.value = true;

      if (props.infinite) {
        setTimeout(() => {
          typeWriter();
        }, 1000);
      }
    }
  }, props.speed);
};

onMounted(() => setTimeout(typeWriter, props.delay));
onBeforeUnmount(() => {
  if (typingInterval.value) {
    clearInterval(typingInterval.value);
    typingInterval.value = null;
  }
});

defineExpose({ isTyping });

watch(
  () => props.text,
  () => {
    typeWriter();
  }
);
</script>

<template>
  <span class="type-writer" :class="customClass">
    {{ displayedText }}
    <span class="cursor">|</span>
  </span>
</template>

<style scoped lang="scss">
.type-writer {
  .cursor {
    animation: blink 1s infinite;
    opacity: 1;
  }
}
@keyframes blink {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}
</style>
